*****************************************
                *                                       *
                *          RingZer0   Presents          *
                *                                       *
                *     "CoSH Crackme3"  by PUSILLUS      *
                *               18/2/99                 *
                *****************************************




Tools:

  SoftIce.


Ciao a tutti, questa volta siamo alle prese con un classico crackme:
 
Lanciando l'eseguibile verra' richiesta nome e password, con il tasto ok viene eseguito 
il Check della password. Come di consueto ho inserito il mio nome, una password a caso 
e settato il canonico BPX GetDlgItemTextA con il Sice, ma il debugger, una volta dato 
l'OK non e' intervenuto! 
Le API usate per leggere da un edit control sono:
GetDlgItemText
GetDlgItemTextA
GetWindowText
GetWindowTextA
Bisognerebbe provarle tutte; allora ho deciso di prendere una strada diversa: 
lanciamo il crackme, una volta che appare la dialogbox entriamo in Sice e 
digitiamo TASK. Compariranno un bel po di processi che il Win sta eseguendo ma 
quello che interessa a noi e' solo il crackme3:

Taskname      SS:SP       StackTop   StackBot   StackLow   TaskDB   hQueue   Events 
crackme3    0000:0000     005ED000   05F0000                11DE    0E47     0000
...

adesso andiamo a vedere quali handle appartengono al nostro processo "HWND crackme3"

Window-Handle   hQueue    SZ    QOwner   Class_Name       Window Procedure
03AC(1)         OE47      32    CRACKME3 #32770 (Dialog)  1457:00000694
 03CC(2)        OE47      32    CRACKME3 Button           ...
 03A8(2)        OE47      32    CRACKME3 Static           ...
 0400(2)        OE47      32    CRACKME3 Static           ...
 03FC(2)        OE47      32    CRACKME3 Edit             ... 
 03E0(2)        OE47      32    CRACKME3 Edit             ... 
 ...

Prendiamo nota della handle della prima Edit control (nel mio caso 03FC) 
E' possibile impostare un break al verificarsi di un Window Message con il comando BMSG,
nel nostro caso il messaggio che ci interessa e' WM_GETTEXT sull'handle dell'edit control
Allora impostiamo "BMSG 03fc WM_GETTEXT" e usciamo da Sice.

Inseriamo i valori nelle dialogbox, nel mio caso "pusillus" e "00000000" e diamo OK.
Il debugger ha brekkato in Kernel.alloc, tramite F12 torniamo indietro dalle varie call e
ci accorgiamo che il programmino fa uso delle MFC42 (MFC42!.text.00...) e la 
funzione usata dalle MFC per leggere il testo e' GetWindowTextA mmm... 
una vera rottura di scatole, infatti io non ho nessuna reference x le MFC e non so
cosa cavolo fanno le funzioni! Comunque Proprio prima della GetWindowTextA noterete:
....
PUSH EAX 
PUSH DWORD PTR [ESI+20]
GetWindowTextA
....

Consultando la reference alle API si vedra' che quel Push EAX corrisponde 
all'indirizzo del buffer dove viene memorizzato il valore letto dall'edit control
bastera' impostare un bpx su quella riga e disabilitare gli altri brakpoint
per conoscere gli indirizzo nel quale viene memorizzato il nome e la pwd. 
La prima volta che ho eseguito il debugging non ho analizzato a fondo il codice
delle MFC e ho proseguito:
Diamo l'ultimo F12 e ci troveremo finalmente al codice del Crackme3.exe, 
e precisamente ci dovremmo trovare alla riga 00401538 dopo la call alla funzione delle 
MFC che come abbiamo visto si occupa di fare un Gettext.

A questo punto mi sono messo a smanettare con i registri e ho scoperto che 
l'indirizzo a cui punta ECX (00760A7C) contiene il nome inserito. In queste cose
ci vuole anche una buona dose di curiosita' e di culo! Probabilmente quella
funzione delle MFC restituisce in ECX l'indirizzo in cui memorizza le stringhe!

disabilitiamo i brekpoint e andiamo avanti con f10 fino ad eseguire la seconda call
alla riga 00401533 e andiamo a leggere in ECX l'indirizzo della Pwd (00760A9C).

---------------------------
:00401521 8B45E0                  mov eax, dword ptr [ebp-20]
:00401524 05E0000000              add eax, 000000E0
:00401529 50                      push eax
:0040152A 8B4DE0                  mov ecx, dword ptr [ebp-20]
:0040152D 81C1A0000000            add ecx, 000000A0

* Reference To: MFC42.Ordinal:0F22, Ord:0F22h
                                  |
:00401533 E866030000              Call 0040189E                <----- Legge Nome
:00401538 8B4DE0                  mov ecx, dword ptr [ebp-20]
:0040153B 81C1E4000000            add ecx, 000000E4
:00401541 51                      push ecx
:00401542 8B4DE0                  mov ecx, dword ptr [ebp-20]
:00401545 83C160                  add ecx, 00000060

* Reference To: MFC42.Ordinal:0F22, Ord:0F22h
                                  |
:00401548 E851030000              Call 0040189E                <----  Legge Pwd
:0040154D 8B55E0                  mov edx, dword ptr [ebp-20]
:00401550 81C2E0000000            add edx, 000000E0
:00401556 52                      push edx
:00401557 8D4DE4                  lea ecx, dword ptr [ebp-1C]
---------------------------


andiamo avanti con F10 fino a raggiungere la riga 00401570: il programma azzera 
tutti i registri mmm... si sta preparando a fare qualcosa di importante, infatti
alla riga 0040157D in eax viene caricato l'indirizzo del nome:


---------------------------
:00401570 33C0                    xor eax, eax        
:00401572 33DB                    xor ebx, ebx          
:00401574 33C9                    xor ecx, ecx
:00401576 B901000000              mov ecx, 00000001            <--  cl<1
:0040157B 33D2                    xor edx, edx
:0040157D 8B45E4                  mov eax, dword ptr [ebp-1C]  <--  EAX<00760A7C

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040158B(C)
|
:00401580 8A18                    mov bl, byte ptr [eax]       <-- bl byte puntato da EAX       
:00401582 32D9                    xor bl, cl                   <-- xor bl e cl  
:00401584 8818                    mov byte ptr [eax], bl       <-- sostituisce il valore puntato da EAX con bl
:00401586 41                      inc ecx                      <-- incrementa ECX       
:00401587 40                      inc eax                      <-- incrementa EAX
:00401588 803800                  cmp byte ptr [eax], 00
:0040158B 75F3                    jne 00401580                 <-- esegue il loop fino a che 
                                                                   non e' stata processata              
                                                                   tutta la stringa.
---------------------------                                                               
                                                                  
Allora avete capito cosa fa questa parte di codice? Ricapitoliamo:

00760A7C >             70 75 73 69 6c 6c 75 73          (pusillus)
           XOR cl      01 02 03 04 05 06 07 08
00760A7C >             71 77 70 6d 69 6a 72 7b


Continuando con F10 arriviamo alla parte di codice in cui viene processata la
Pwd:

---------------------------
:0040158D 33C0                    xor eax, eax
:0040158F 33DB                    xor ebx, ebx
:00401591 33C9                    xor ecx, ecx
:00401593 B90A000000              mov ecx, 0000000A            <-- ECX<0A
:00401598 33D2                    xor edx, edx
:0040159A 8B45F0                  mov eax, dword ptr [ebp-10]  <-- EAX<00760A9C 

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004015A8(C)
|
:0040159D 8A18                    mov bl, byte ptr [eax]       <-- bl< valore puntato da eax
:0040159F 32D9                    xor bl, cl                   <-- xor bl e cl
:004015A1 8818                    mov byte ptr [eax], bl       <-- valore puntato da eax < bl
:004015A3 41                      inc ecx
:004015A4 40                      inc eax
:004015A5 803800                  cmp byte ptr [eax], 00       <-- esegue il loop fino che non ha
:004015A8 75F3                    jne 0040159D                     processato l'intera stringa
---------------------------

Niente di diverso da prima solo che in questo caso CL viene inizializzato con 0A:


00760A9C >             30 30 30 30 30 30 30 30          (00000000)
           XOR cl      0A 0B 0C 0D 0E 0F 10 11
00760A9C >             3A 3B 3C 3D 3E 3F 20 21


andando avanti ci accorgiamo che i valori delle due stringhe cosi' modificati
vengono confrontati:

---------------------------
:004015AA 8B45E4                  mov eax, dword ptr [ebp-1C]  <-- 00760A7C
:004015AD 8B55F0                  mov edx, dword ptr [ebp-10]  <-- 00760A9C

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004015BF(C)
|
:004015B0 33C9                    xor ecx, ecx
:004015B2 8A18                    mov bl, byte ptr [eax]       <-- bl< val. puntato da eax
:004015B4 8A0A                    mov cl, byte ptr [edx]       <-- cl< val. puntato da edx
:004015B6 3AD9                    cmp bl, cl                   <-- comparazione
:004015B8 7509                    jne 004015C3                 <-- non uguali salta a "ERROR"
:004015BA 40                      inc eax
:004015BB 42                      inc edx
:004015BC 803800                  cmp byte ptr [eax], 00       <-- controllo su fine stringa
:004015BF 75EF                    jne 004015B0                 <-- riesegue il ciclo x tutta la stringa 
:004015C1 EB16                    jmp 004015D9                 <-- salta a "YOU DID IT"         

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00401503(U), :0040151C(U), :004015B8(C)
|
:004015C3 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"ERROR"
                                  |
:004015C5 686C304000              push 0040306C

* Possible StringData Ref from Data Obj ->"One of the Details you entered "
                                        ->"was wrong"
                                  |
:004015CA 6840304000              push 00403040
:004015CF 8B4DE0                  mov ecx, dword ptr [ebp-20]

* Reference To: MFC42.Ordinal:1080, Ord:1080h
                                  |
:004015D2 E8BB020000              Call 00401892
:004015D7 EB14                    jmp 004015ED

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004015C1(U)
|
:004015D9 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"YOU DID IT"
                                  |
:004015DB 6834304000              push 00403034

* Possible StringData Ref from Data Obj ->"Well done,Cracker"
                                  |
:004015E0 6820304000              push 00403020
---------------------------

Arrivati a questo punto non ci resta che calcolare una password corretta
per il nome inserito:

        71 77 70 6d 69 6a 72 7b  <-- valori calcolati dal programma sul nome
        0A 0B 0C 0D 0E 0F 10 11  <-- xoring
        7B 7C 7C 60 67 65 62 6A  <-- password corretta: {||`gebj
        
        
Facile no?


Pusillus.